package com.settlement.system.controller;

import cn.hutool.http.HttpUtil;
import com.settlement.system.common.enums.ReturnStatusEnum;
import com.settlement.system.common.enums.RpaChargeTaskStatusEnum;
import com.settlement.system.common.exception.ServiceException;
import com.settlement.system.common.annotation.LoggerProfile;
import com.settlement.system.model.entity.common.*;
import com.settlement.system.model.param.*;
import com.settlement.system.reply.ListResponse;
import com.settlement.system.reply.ObjectDataResponse;
import com.settlement.system.service.*;
import com.settlement.system.common.util.common.FasUtil;
import com.settlement.system.common.util.common.HttpClientCommonUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanMap;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;

import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * RPA3.0专项费用充值-任务表 前端控制器
 * @author xiaochuan
 * @since 2021-03-09
 */

@Slf4j
@Api(tags = "RPA3.0专项费用充值-任务表",description = "RPA3.0专项费用充值-任务表")
@RestController
@RequestMapping("/tblRpaChargeTask")
public class TblRpaChargeTaskController extends MergeApiExcelController<TblRpaChargeTask, RpaChargeTaskGetApiRequestParams> {

    @Resource
    private ITblRpaChargeTaskService tblRpaChargeTaskService;

    @Resource
    private ITblAdvertiseMarketAccountService tblAdvertiseMarketAccountService;

    @Resource
    private ITblRpaBankCardService tblRpaBankCardService;

    @Resource
    private ITblRrChannelService tblRrChannelService;

    @Override
    public IBaseService init() {
        return tblRpaChargeTaskService;
    }

    @Override
    public Class<?> getModelClass() {
        return TblRpaChargeTask.class;
    }

    @Value("${rpa.chargeTask.updateUrl}")
    private String UPDATE_URL;

    public static final String CHECK_URL = "http://172.17.17.116:8080/oa_api/xl/workflow/XL_CW19/queryDetailAmount";
            //"http://10.234.9.102:8080/oa_api/xl/workflow/XL_CW19/queryDetailAmount";

    /**
     * 每日可用余额最高1500*100W=15亿
     * RPA 可用银行卡查询接口  只获取一个银行卡号（只有一个） 限额去掉（为了方便，就改为一个很大的数：15亿）
     */
    public static final BigDecimal MAX_AVAILABLE_BALANCE = new BigDecimal(1500*10000*100+"");

    @Override
    protected void setParamsModel(Map<String, Object> model) {
        FasUtil.formatInQueryCondition(model, "ncShopNo", "loginAccount", "channelNo", "channelName", "oaProcessNo", "processRequestId", "shopAccount","taskStatus","detailNumberId");
        super.setParamsModel(model);
    }

    @Override
    protected void setFootModel(Map<String, Object> result, Map<String, Object> model) throws ServiceException {
        TblRpaChargeTask foot = tblRpaChargeTaskService.getFoot(model);
        result.put("foot", foot==null? getModelClass():foot);
    }

    @Override
    protected void saveData(List<TblRpaChargeTask> datas) throws ServiceException {
        super.saveData(datas);
    }

    @Override
    protected String verifyData(List<TblRpaChargeTask> list) {
        String message = super.verifyData(list);
        if(StringUtils.isNotEmpty(message)){
            return message;
        }
        for (TblRpaChargeTask detail : list) {
            message = verify(detail);
            if (!StringUtils.isEmpty(message)) {
                return message;
            }
        }
        return null;
    }

    /**
     * 验证数据
     *
     * @param detail
     * @return
     */
    private String verify(TblRpaChargeTask detail) {
        detail.setTaskStatus(RpaChargeTaskStatusEnum.UNPAID.getNo());
        try{
            TblAdvertiseMarketAccount account = tblAdvertiseMarketAccountService.getByNcShopNo(detail.getNcShopNo());
            if(account!=null){
                detail.setShopAccount(account.getShopAccountName());
                detail.setNcShopName(account.getNcShopName());
                detail.setLoginAccount(account.getLoginAccount());
            }else{
                return "无法通过ncShopNo "+detail.getNcShopNo()+"获取账号";
            }
        } catch (ServiceException e) {
            e.printStackTrace();
            return "通过ncShopNo获取账号出错";
        }
        try{
            String detailNumberId = detail.getDetailNumberId();
            TblRpaChargeTask byDetailNumberId = tblRpaChargeTaskService.getByDetailNumberId(detailNumberId);
            if(byDetailNumberId!=null){
                return "明细序号ID "+detailNumberId+" 已存在";
            }
        } catch (ServiceException ex) {
            log.error("getByDetailNumberId error",ex);
            return ReturnStatusEnum.REQUEST_ABNORMAL.getText();
        }
        try{
            String channelName = detail.getChannelName();
            if(StringUtils.isNotBlank(channelName)){
                String noByName = tblRrChannelService.getNoByName(channelName);
                detail.setChannelNo(noByName);
            }
            boolean b = checkApplyForAmount(detail);
            if(b==false){
                detail.setTaskStatus(RpaChargeTaskStatusEnum.CHECK_APPLY_FOR_AMOUNT_FAILURE.getNo());
                detail.setDetailNumberId(detail.getDetailNumberId());
            }
        }catch (ServiceException ex){
            return ex.getMessage();
        }
        return null;
    }

    /**
     * 校验OA申请金额
     * @param task
     * @throws IOException
     */
    boolean checkApplyForAmount(TblRpaChargeTask task) throws ServiceException {
        Map<String, String> paramMap = new HashMap<>(16);
        paramMap.put("detailId",task.getDetailNumberId());
        try{
            String s = HttpClientCommonUtil.doPost(CHECK_URL, paramMap);
            System.out.println(s);
            JSONObject json = (JSONObject) JSONObject.parse(s);
            if(json!=null){
                String code = (String) json.get("code");
                String msg = (String) json.get("msg");
                Object o = json.get("data");
                final String failure = "失败";
                final String success = "成功";
                if(String.valueOf(-1).equals(code)&&msg.contains(failure)){
                    if(o instanceof String){
                        throw new ServiceException(o.toString());
                    }
                }
                if(String.valueOf(1).equals(code)&&success.equals(msg)){
                    if(o instanceof JSONObject){
                        JSONObject data = (JSONObject) o;
                        if(data!=null){
                            data.put("applyForAmount",data.get("amount"));
                            data.put("oaProcessNo",data.get("requestMark"));
                            data.put("processRequestId",data.get("requestId"));
                            data.put("detailNumberId",data.get("detailId"));
                            TblRpaChargeTask dataTask =
                                    JSON.parseObject(data.toJSONString(), TblRpaChargeTask.class);
                            if(task.getOaProcessNo().equals(dataTask.getOaProcessNo()) &&
                                    task.getProcessRequestId().equals(dataTask.getProcessRequestId()) &&
                                    task.getDetailNumberId().equals(dataTask.getDetailNumberId()) &&
                                    task.getApplyForAmount().compareTo(dataTask.getApplyForAmount())==0){
                                return true;
                            }
                        }
                    }
                }
            }
        }catch (Exception ex){
            log.error("校验OA申请金额异常", ex);
            throw new ServiceException("校验OA申请金额异常", ex);
        }

        return false;
    }

    /**
     * RPA3.0专项充值 获取任务列表
     *
     * @return
     */
    @ApiOperation(value = "RPA3.0专项充值 获取任务列表")
    @LoggerProfile(methodNote="RPA3.0专项充值 获取任务列表")
    @RequestMapping(value = "/api/list", method = RequestMethod.POST)
    public ObjectDataResponse<ListResponse<RpaChargeTaskGetApiReponseParams>> list(@RequestBody BasePager<RpaChargeTaskGetApiRequestParams> model) {
        ListResponse<RpaChargeTaskGetApiReponseParams> result = new ListResponse<>();
        try {
            String message = verifyBean(model.getModel());
            if (!StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), message);
            }
            Map<String, Object> params = getRequestParam(model.getModel());
            setParamsModel(params);
            int count = baseService.selectCount(params);
            List<RpaChargeTaskGetApiReponseParams> rows = new ArrayList<>();
            List<TblRpaChargeTask> list = baseService.selectByPage(new SinglePage(model), params,
                    "id", "ASC");
            list.forEach(task->{
                task.setApplyForAmount(task.getApplyForAmount().setScale(2, RoundingMode.HALF_UP));
                BeanMap beanMap = new BeanMap(task);
                RpaChargeTaskGetApiReponseParams responseParams =
                        JSON.parseObject(JSON.toJSONString(beanMap), RpaChargeTaskGetApiReponseParams.class);
                rows.add(responseParams);
            });
            result.setTotal(count);
            result.setRows(rows);
        } catch (Exception ex) {
            log.error("获取列表出错", ex);
            return new ObjectDataResponse(500, "服务器异常");
        }
        return new ObjectDataResponse<ListResponse<RpaChargeTaskGetApiReponseParams>>(result, 200, "success");
    }



    /**
     * 更新
     *
     * @return
     */
    @ApiOperation(value = "更新")
    @LoggerProfile(methodNote="更新")
    @RequestMapping(value = "/api/update", method = RequestMethod.POST)
    public ObjectDataResponse update(@RequestBody RpaChargeTaskUpdateApiRequestParams model) {
        try {
            String message = verifyBean(model);
            if (!StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), message);
            }
            List<RpaChargeTaskUpdateApiRequestParams> requestParamsList = new ArrayList<>();
            requestParamsList.add(model);
            tblRpaChargeTaskService.updateByParam(requestParamsList);
            return new ObjectDataResponse(200, "success");
        } catch (Exception ex) {
            log.error("更新出错", ex);
            return new ObjectDataResponse(500, "服务器异常");
        }
    }

    /**
     * 批量更新
     * @param models
     * @return
     */
    @ApiOperation(value = "批量更新")
    @LoggerProfile(methodNote="批量更新")
    @RequestMapping(value = "/api/batchUpdate", method = RequestMethod.POST)
    public ObjectDataResponse batchUpdate(@RequestBody List<RpaChargeTaskUpdateApiRequestParams> models) {
        try {
            String message = verifyBeans(models);
            if (!StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), message);
            }
            tblRpaChargeTaskService.updateByParam(models);

            return new ObjectDataResponse(200, "success");
        } catch (Exception ex) {
            log.error("更新出错", ex);
            return new ObjectDataResponse(500, "服务器异常");
        }
    }

    /**
     * 可用银行卡查询接口
     *
     * @return
     */
    @ApiOperation(value = "可用银行卡查询接口")
    @LoggerProfile(methodNote="可用银行卡查询接口")
    @RequestMapping(value = "/api/getAvailableBankCard", method = RequestMethod.POST)
    public ObjectDataResponse<TblRpaBankCardApiResponseParams> getAvailableBankCard(@RequestBody TblRpaBankCardApiRequestParams model) {
        TblRpaBankCardApiResponseParams result = new TblRpaBankCardApiResponseParams();

        try {
            String message = verifyBean(model);
            if (!StringUtils.isEmpty(message)) {
                return new ObjectDataResponse(ReturnStatusEnum.CHECK_FAILURE.getValue(), message);
            }

            result.setProcessRequestId(model.getProcessRequestId());

            List<Map<String,Object>> usedBalances = tblRpaChargeTaskService.getAvailableBalance();

            Map<String,BigDecimal> usedBalancesMap = new HashMap<>(16);
            usedBalances.forEach(usedbalance ->{
                usedBalancesMap.put((String) usedbalance.get("PAYMENTACCOUNT"), (BigDecimal) usedbalance.get("USEDBALANCE"));
            });

            List<TblRpaBankCard> cardList = tblRpaBankCardService.selectByParam(new HashMap<>(16));
            for(TblRpaBankCard card : cardList){
                BigDecimal usedBalance = BigDecimal.ZERO;
                if(!CollectionUtils.isEmpty(usedBalancesMap)){
                    usedBalance = usedBalancesMap.get(card.getCardNo());
                    if(usedBalance==null){
                        usedBalance = BigDecimal.ZERO;
                    }
                }
                BigDecimal availableBalance = MAX_AVAILABLE_BALANCE.subtract(usedBalance);
                if(availableBalance.compareTo(model.getProcessTotalAmount()) >= 0){
                    result.setIfExistAvailableBankCard("Y");
                    result.setCardNo(card.getCardNo());
                    result.setAccountName(card.getAccountName());
                    break;
                }
            }

        } catch (Exception ex) {
            log.error("查询可用银行卡出错", ex);
            return new ObjectDataResponse(500, "服务器异常");
        }
        return new ObjectDataResponse<TblRpaBankCardApiResponseParams>(result, 200, "success");
    }


    @Override
    protected ObjectDataResponse update(@RequestBody TblRpaChargeTask model, HttpServletRequest request) throws ServiceException {
        try {
            if (String.valueOf(1).equals(model.getTaskStatus())) {
                TblRpaChargeTask byDetailNumberId = tblRpaChargeTaskService.getByDetailNumberId(model.getDetailNumberId());
                List<Map<String, String>> requestList = new ArrayList<>();
                Map<String, String> paramMap = new HashMap<>(16);
                paramMap.put("detailId", model.getDetailNumberId());
                paramMap.put("topUpStatus", model.getTaskStatus());
                paramMap.put("bankNo", byDetailNumberId.getBankOrder());
                paramMap.put("requestId", byDetailNumberId.getProcessRequestId());
                requestList.add(paramMap);
                Map<String, String> dataMap = new HashMap<>();
                dataMap.put("data", JSON.toJSONString((requestList)));
                log.info("请求更新OA充值任务状态: paramMap={}", dataMap);
                int oaStatus = 0;
                for (int i = 1; i <= 3; i++) {
                    try {
                        String response = HttpClientCommonUtil.doPost(UPDATE_URL, dataMap);
                        log.info("更新OA充值任务状态返回: response= {}", response);
                        JSONObject responseJson = (JSONObject) JSONObject.parse(response);
                        log.info("更新OA充值任务状态: responseJson= {}", responseJson);
                        if (responseJson != null) {
                            String code = (String) responseJson.get("code");
                            log.info("更新OA充值任务状态 code={}", code);
                            String msg = (String) responseJson.get("msg");
                            log.info("更新OA充值任务状态 msg={}", msg);
                            if (String.valueOf(1).equals(code) && msg.contains("成功")) {
                                oaStatus = 1;
                                break;
                            }
                        }
                    } catch (Exception ex) {
                        log.error("更新OA任务状态异常", ex);
                        throw new ServiceException("更新OA任务状态异常", ex);
                    }
                }
                if (oaStatus == 0){
                    throw new ServiceException("更新OA任务状态失败");
                }
            }

            this.setDefualt(model);
            this.setModelValue(model);
            baseService.update(model);
            return new ObjectDataResponse(200, "更新成功");
        } catch (Exception ex) {
            throw new ServiceException("更新失败，请联系管理员！",ex);
        }
    }
}

